#include <iostream>
#include <memory>
#include <list>
using std::cout;
using std::endl;
using std::list;
using std::unique_ptr;

class Observer
{
public:
    virtual void update(int status) = 0; 
    virtual ~Observer() {}
};

class Subject
{
public:
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify() = 0;
    virtual ~Subject() {}
};

class ConcreateSubject
    : public Subject
{
public:
    virtual void attach(Observer* observer) override{
        for(auto it = _lobs.begin(); it != _lobs.end(); ++it){
            if(*it == observer) { return; }
        }
        _lobs.push_back(observer);
    }
    virtual void detach(Observer* observer) override{
        for(auto it = _lobs.begin(); it != _lobs.end(); ++it){
            if(*it == observer) { _lobs.erase(it); return; }
        }     
    }
    virtual void notify(){
        for(auto elem : _lobs){
            elem->update(_status);
        }   
    }
    virtual ~ConcreateSubject() {}
    void set_status(int status){ _status = status; notify(); }
    int get_status(){ return _status;}
private:
    list<Observer*> _lobs;
    int _status;
};



class ConcreateObserver_1
    : public Observer
{
public:
    virtual void update(int status) override { cout << "ConcreateObserver_1" << endl;} 
};
class ConcreateObserver_2
    : public Observer
{
public:
    virtual void update(int status) override { cout << "ConcreateObserver_2" << endl;} 
};
class ConcreateObserver_3
    : public Observer
{
public:
    virtual void update(int status) override { cout << "ConcreateObserver_3" << endl;} 
};


int main()
{
    unique_ptr<Observer> u1(new ConcreateObserver_1());
    unique_ptr<Observer> u2(new ConcreateObserver_2());
    unique_ptr<Observer> u3(new ConcreateObserver_3());


    unique_ptr<ConcreateSubject> sub(new ConcreateSubject());

    sub.get()->attach(u1.get());
    sub.get()->attach(u2.get());
    sub.get()->attach(u3.get());

    cout << sub.get()->get_status() << endl;
    sub.get()->set_status(10);

    return 0;
}